package fr.tocchisu.movies.services.parsers;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class PlainTextInterfaceParser<T extends Serializable> {
    private long currentLineNumber;
    private final static Logger LOGGER = LoggerFactory.getLogger(PlainTextInterfaceParser.class);
    protected static final SimpleDateFormat YEAR_DATE_FORMAT = new SimpleDateFormat("yyyy");

    protected final void read() {
	String line = null;
	BufferedReader bufferedReader = null;
	Long startTime = new Date().getTime();
	try {
	    beforeFileParsed();
	    bufferedReader = new BufferedReader(new FileReader(getFilePath()));
	    int nbParsedObjects = 0;
	    Pattern pattern = Pattern.compile(getLinePattern());
	    while ((line = bufferedReader.readLine()) != null) {
		currentLineNumber++;
		LOGGER.info("Parsing L." + currentLineNumber + " : " + line);
		Matcher matcher = pattern.matcher(line);
		if (matcher.find()) {
		    beforeLineParsed();
		    T t = parseLine(matcher, line, currentLineNumber);
		    nbParsedObjects++;
		    afterLineParsed(t);
		} else {
		    LOGGER.warn("Unparsable line " + currentLineNumber + " : -->" + line + "<--");
		}
	    }
	    LOGGER.info(nbParsedObjects + " objects parsed");
	} catch (FileNotFoundException e) {
	    LOGGER.error("Fichier introuvable", e);
	} catch (Exception e) {
	    String message = "Error while processing file " + getFilePath();
	    if (line != null) {
		message += System.getProperty("line.separator") + "line " + currentLineNumber + " : " + line;
	    }
	    LOGGER.error(message, e);
	} finally {
	    if (bufferedReader != null) {
		try {
		    bufferedReader.close();
		} catch (IOException e) {
		    LOGGER.error(e.getMessage(), e);
		}
	    }
	    afterFileParsed();
	    LOGGER.info("Treatment duration : " + (new Date().getTime() - startTime) + " ms");
	}
    }

    public abstract T parseLine(Matcher matcher, String line, Long lineNumber);

    protected abstract String getFilePath();

    protected void beforeFileParsed() {
    }

    protected void beforeLineParsed() {
    }

    protected void afterFileParsed() {
    }

    protected void afterLineParsed(T t) {
    }

    public static void main(String[] args) {
	new PlainTextMovieInterfaceParser().read();
    }

    protected abstract String getLinePattern();

    protected Date getDate(String date, DateFormat dateFormat) throws ParseException {
	return date == null ? null : dateFormat.parse(date);
    }

}
